using System;
using System.Threading;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace SmsServerClient
{
	/// <summary>
	/// Summary description for SmsListener.
	/// </summary>
	public class SmsListener : IDisposable
	{
		#region Private and public data members
		private int disposed = 0;
        public int bDone = 0;
        Thread workerThread = null;
        public delegate void FilterSmsReceivedDelegate(SmsClass Message);
        public event FilterSmsReceivedDelegate FilterSmsReceived;
		#endregion

		#region SmsListener constructor
		/// <summary>
		/// Constructor of SmsListener class. We start a managed worker thread is started 
		/// that waits for Sms messages being send from the unmanaged DLL and passes them on
		/// to any event handler that is interested in the data.
		/// </summary>
		public SmsListener()
		{
			
        }

        public void InitThread()
        {
            bool Response = UnmanagedAPI.CaptureSmsMessages();
            Interlocked.Exchange(ref bDone, 0);
            if (workerThread == null)
            {
                workerThread = new Thread(new ThreadStart(CheckForData));
                workerThread.Start();
            }
        }

        public void EndThread()
        {
            Interlocked.Exchange(ref bDone, 1);
            Thread.Sleep(100);
            UnmanagedAPI.TerminateSmsMessagePassing();
            if (workerThread != null)
            {
                //workerThread.Abort();
                workerThread = null;
            }
        }
		#endregion
		#region CheckForData
		/// <summary>
		/// This is the worker thread of the SmsListener class. After construction
		/// of the object this class runs continuously, until SmsListener is disposed.
		/// The worker thread P/Invokes into unmanaged code to SmsMessageAvailable. Inside
		/// this function, execution is blocked until new (asynchronous) data (an Sms message)
		/// is available. If data is it is simply passed to a listbox, using Control.Invoke.
		/// </summary>
		private void CheckForData()
		{
			StringBuilder sbSms = new StringBuilder(1464);
			StringBuilder sbPhoneNr = new StringBuilder(64);
            FILETIME sbFt = new FILETIME();
            int count = 0;
            while (bDone==0)
            {
                try
                {
                    
                    if (UnmanagedAPI.SmsMessageAvailable(sbSms, sbPhoneNr,ref sbFt,ref count))
                    {
                        SmsClass NewSms = new SmsClass();
                        NewSms.Body = sbSms.ToString();
                        NewSms.Number = sbPhoneNr.ToString();
                        NewSms.Time = HelperClass.FileTime2DateTime(sbFt);
                       
                       if (FilterSmsReceived != null)
                            FilterSmsReceived(NewSms);
                    }
                    Thread.Sleep(50);
                }
                catch
                {
                }
            }
		}
		#endregion
		#region Dispose function
		/// <summary>
		/// Dispose(bool disposing) executes in two distinct scenarios.
		///   If disposing equals true, the method has been called directly or indirectly 
		///     by user code. Managed and unmanaged resources can be disposed.
		///   If disposing equals false, the method has been called by the 
		///     runtime from inside the finalizer and you should not reference 
		///     other objects. Only unmanaged resources should be disposed.
		/// </summary>
		/// <param name="disposing">Called directly (true) or indirectly (false)</param>
		private void Dispose(bool disposing)
		{
			// Check to see if Dispose has already been called.
			if(this.disposed == 0)
			{
				// We don't really have managed resources to dispose, so just
				// remove the unmanaged resources, meaning getting rid
				// of the (managed) worker thread and freeing the used DLL.
                Interlocked.Exchange(ref bDone, 1);
                Thread.Sleep(50);
				UnmanagedAPI.TerminateSmsMessagePassing();
                Thread.Sleep(50);
                if(workerThread!=null)
                    workerThread.Abort();
                workerThread = null;

			}
            Interlocked.Exchange(ref disposed, 0);
        }
		#endregion

		#region SmsListener finalizer
		/// <summary>
		/// Use C# destructor syntax for finalization code.
		/// This destructor will run only if the Dispose method does not get called.
		/// </summary>
		~SmsListener()      
		{
			// Do not re-create Dispose clean-up code here.
			// Calling Dispose(false) is optimal in terms of
			// readability and maintainability.
			Dispose(false);
		}
		#endregion
		
		#region IDisposable Members

		public void Dispose()
		{
			Dispose(true);
			// This object will be cleaned up by the Dispose method.
			// Therefore, you should call GC.SupressFinalize to
			// take this object off the finalization queue 
			// and prevent finalization code for this object
			// from executing a second time.
			GC.SuppressFinalize(this);
		}

		#endregion
	}
}
